iT邦幫忙

2024 iThome 鐵人賽

DAY 4
0
Modern Web

一起來玩圖像編輯器:Fabric.js 的實戰修煉系列 第 4

Day4-來概念解構 Fabric.js 吧 (2)-物件導向特性與物件(Object)與擴展機制(extend)

  • 分享至 

  • xImage
  •  

物件導向的 fabric.js

繼昨天講了那麼多特性,各種蛛絲馬跡都指出,他是一個 物件導向架構
以下進行各種比對分析:

Fabric.js 把所有畫布上的東西都當作物件。
物件導向架構

物件有 Rect(矩形)、Circle(圓形)、Image(圖片)等都繼承自基本的 Fabric.Object 類別,而特定形狀如 Fabric.Rect 則進一步擴展這個基類。
類別和繼承 (Classes and Inheritance)

每個物件封裝了自己的屬性和方法。以下舉例:
屬性:一個矩形物件會有自己的寬度、高度、位置等屬性
方法:移動、縮放等方法。
封裝 (Encapsulation)

不同類型的物件如何對相同的方法(如 render()toObject()animate())有不同的實現

// rect 和 circle 是不同形狀的物件,用相同的 animate() 方法,但實現出來的視覺結果會不一樣
rect.animate('left', '+=100', {
    onChange: canvas.renderAll.bind(canvas),
    duration: 1000
});

circle.animate('top', '+=100', {
    onChange: canvas.renderAll.bind(canvas),
    duration: 1000
});

多型 (Polymorphism)

你可以為特定物件或整個畫布添加事件監聽器, 使用物件導向的方式來處理事件。
事件處理 (Event Handling)

由於其物件導向的設計,Fabric.js 很容易擴展。
你可以創建自定義的物件類型,繼承現有的類別並添加新功能。
可擴展性 (Extensibility)

這種物件導向的方法使 Fabric.js 變得強大且靈活,允許開發者以一種結構化和可維護的方式來處理複雜的畫布操作。

如果對於物件導向不是很清楚的話推薦這一篇:
物件導向的三大特性 : 封裝,繼承,多型
他用淺顯易懂的方式解釋這些特性


物件(Object)

講完物件導向特性後,就讓我們來深入理解 fabric.js 的物件吧:

一個 fabric.js 物件長怎樣?

這是一個矩形物件,使用方式基本上就是 new 一個他 (像是 javascript new 一個物件一樣),並可以直接加屬性在這個物件上

const rect = new fabric.Rect({
   left: 100,
   top: 100,
   fill: 'red',
   width: 50,
   height: 50
});

主要物件類別 -

Main rendering surface(簡稱畫布)

fabric.Canvasfabric.StaticCanvas

  • 代表整個工作區
  • 管理所有物件和交互

種類

動態畫布靜態畫布 兩種:

  • fabric.Canvas
    動態畫布,我們前面舉的例子都使使用這,可以處理使用者動態交互關係
  • fabric.StaticCanvas
    靜態畫布 (StaticCanvas) 沒有互動層和事件處理功能
    • 無法拖動物件、繪圖、註冊點擊事件等
    • 使用於你只需要渲染場景或無法處理使用者互動的情況,例如在 server 端渲染畫布。

動態畫布舉例:

const canvas = new fabric.Canvas('canvas');

// 常見可以設置的屬性
const canvas = new fabric.Canvas('canvas', {
    backgroundColor: '#fff',
    selection: true,
    preserveObjectStacking: true,
    
    hoverCursor: 'pointer',
    defaultCursor: 'default',
});

// 也可以事後再加上去
// isDrawingMode 及時控制現在是否為繪畫模式
canvas.set({
    isDrawingMode: false,
})
fabric.Canvas 常用的屬性:
  • backgroundColor: 設置畫布的背景顏色。

  • selection: 是否允許選擇多個物件,設定 false 的話一次只能選取一個物件

  • preserveObjectStacking: 當選擇多個物件時,是否保持物件的堆疊順序。

  • hoverCursor: 當滑鼠懸停在物件上時顯示的游標樣式。

  • defaultCursor: 當滑鼠在畫布上但不在物件上時顯示的游標樣式。

  • isDrawingMode: 是否啟用繪圖模式。

2D shapes inheriting from fabric.Object(繼承fabric.Object 的物件)

JSDoc: Class: Object (fabricjs.com)

  • 所有Fabric物件的基類

fabric.Object 共通屬性和方法

常用屬性在上一篇已介紹,今天不再贅述

圖形類:

fabric.Rect:矩形對象
fabric.Circle:圓形對象
fabric.Triangle:三角形對象
fabric.Line:線條對象
fabric.Polygon:多邊形對象
fabric.Polyline:折線對象
fabric.Ellipse:橢圓形對象

文字類:

JSDoc: Class: Text (fabricjs.com)
fabric.Text:文本對象
fabric.IText:可編輯文本對象

  • 處理文本物件

  • 提供文字樣式和排版功能

    fabric.Text 特有的其他屬性(常用):

    • text: 文本內容。
    • fontSize: 字體大小。
    • fontWeight: 字體粗細。
    • fontFamily: 字體家族。
    • fontStyle: 字體樣式(如 normalitalic)。
    • textAlign: 文本對齊方式(如 leftcenterright)。
    • lineHeight: 行高。
    • charSpacing: 字符間距。

圖像:

JSDoc: Class: Image (fabricjs.com)
fabric.Image

  • 處理圖片物件
  • 提供濾鏡和圖片操作功能

路徑:

JSDoc: Class: Path (fabricjs.com)
fabric.Path

  • 用於創建複雜形狀和路徑

  • 支持SVG路徑指令

    特有屬性(常用)

    • path: 路徑數據,通常是一個包含路徑命令的數組。
    • pathOffset: 路徑的偏移量,包含 x 和 y 屬性,用於調整路徑的起始點。
    • fillRule: 填充規則,決定如何填充路徑(如 nonzero 或 evenodd)。
    • strokeDashArray: 描邊的虛線樣式,通常是一個數字數組。
    • strokeDashOffset: 描邊虛線的偏移量。
    • strokeLineCap: 描邊的端點樣式(如 buttroundsquare)。
    • strokeLineJoin: 描邊的連接樣式(如 miterroundbevel)。
    • strokeMiterLimit: 描邊的斜接限制。
    • transformMatrix: 用於變換路徑的矩陣。

群組:

  • 管理物件群組

  • 允許整體操作多個物件
    fabric.Group:對象組
    fabric.PathGroup:路徑組對象

    特有屬性(常用)

    • objects: 包含在該組中的對象數組。。
    • subTargetCheck: 是否檢查組內的子目標(默認為 false)。
    • useSetOnGroup: 是否在組內的對象上應用組的屬性(默認為 false)。
    • dirty: 標記組是否需要重新渲染(默認為 false)。

官方文件

Fabric.js 的物件模型層次結構


擴展機制

Fabric.js提供了擴展現有類的機制,允許開發者添加自定義方法和屬性:

  • fabric.util.createClass(): 用於創建新類
  • fabric.[ClassName].prototype.extend(): 擴展現有 class

這個機制可以玩的東西很多!除了擴展,你也可以擴展原型來覆蓋掉既有的 prototype(在不玩壞現有功能的前提下),這特性讓使用 fabric.js 的自由度變很大。

後續會慢慢介紹更多關於這塊的例子~


統整

為何要大費周章地介紹 fabric.js 的物件導向特性呢?
以下是一些使用這些特性的例子:

例子1:繼承的例子

在製作物件的控制項時,可以擴展 fabric.Object 類並覆寫其 controls 屬性,這樣所有物件出生的時候都可直接繼承 fabric.Object上我們客製化的控制項
而不是傻傻的每新增一個/一種物件就做一次(像我之前一樣不要學)
(後續會詳細介紹製作物件的控制項的例子)
https://ithelp.ithome.com.tw/upload/images/20240807/20168354QIDw8IGLgc.png

例子2:extend/覆蓋prototype的例子

fabric.js 沒有內建 redo/undo的功能,如果我們在 prototype 裡新增這功能:

fabric.Canvas.prototype.redo = function (callback) {
...前進邏輯
}
fabric.Canvas.prototype.undo = function (callback) {
...回復邏輯
}

你之後在畫布(全域)上就可以直接取用此功能了!🎉
canvas.undo();
canvas.undo();
以此類推,很多功能你可以自己寫 extend 的 api 來取用 or 或是覆蓋舊有的屬性


是我自己後來再回來看,理解這些物件導向特性可以更精準、有效率的使用 fabric.js 。
(以下省略一萬字摸索過程中的血與淚QAQ)

明天來繼續聊聊 fabric.js 的事件(event)與渲染(render)


上一篇
Day3- 來概念解構 Fabric.js 吧 (1) - 核心概念
下一篇
Day5- 來概念解構 Fabric.js 吧 (3)-事件(events)與生命週期
系列文
一起來玩圖像編輯器:Fabric.js 的實戰修煉30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言